#include <ESP8266WiFi.h>       //安装esp8266arduino开发环境
#include <LiquidCrystal_I2C.h> //引用LCD的I2C库
#include <ArduinoJson.h>       // 使用json发送数据
#include <SoftwareSerial.h>
#include <AliyunIoTSDK.h> //引入阿里云 IoT SDK
//需要安装crypto库、PubSubClient库
static WiFiClient espClient;

/* 连接您的WIFI SSID和密码 */
#define WIFI_SSID "esp8266test"
#define WIFI_PASSWD "qwertyui"

/* 设备的三元组信息*/
#define PRODUCT_KEY "gdb9d8QpRRe"
#define DEVICE_NAME "test02"
#define DEVICE_SECRET "ead60e25a653b904735d29f2cb736d10"
#define REGION_ID "cn-shanghai"

LiquidCrystal_I2C lcd(0x27, 16, 2);
SoftwareSerial toArduinoA(14, 12); //RX=d5,TX=d6，软串口

/* 变量初始化*/
// 特殊全局变量
unsigned long lastMs = 0; // 用来实现每隔x秒发送一次
unsigned char count = 0;  // 计数器
// int displayStatus = 0;    // lcd显示状态
String S_val = ""; //存储串口接收的字符串
// 传感器
/* 环境大类*/
bool autoMode; // FullAutoModeSwitch: 全自动开关，由用户设置，不发送
bool autoMode_prev;
int illumination, illumination_sum; // 传感器读取的环境亮度，是状态量
float RH, T, RH_sum, T_sum;         // 温湿度模块，状态量
int brightness;                     // Brightness: 设备亮度,自动模式下由传感器决定，否则由用户设置，值由最后时刻值决定
int fan;                            // FanState: 风扇。同设备亮度
bool curtain;                       // CurtainOperation: 窗帘状态，同设备亮度
int brightness_prev, fan_prev;      //上一次的状态量
bool curtain_prev;                  //上一次的状态量
/* 防盗大类*/
bool antiTheft; //AntiTheft: 防盗是否开启，由用户设置，不发送
bool antiTheft_prev;
bool motion, collide, tilt;                             // MotionAlarmState红外、CollideStatus碰撞、OverTiltError倾斜；
bool alarmState;                                        // AlarmState警报状态，当前面几个传感器状态不都为0且antiTheft打开时为1，发送,不过这个可以放到主体那里
bool motion_sum, collide_sum, tilt_sum, alarmState_sum; // 用来检测是否出现过1
//----------------------------------------------------------------
void setup()
{
  lcd.init();
  lcd.backlight();
  /* initialize serial for debugging */
  Serial.begin(9600);

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  //连接到wifi
  wifiInit(WIFI_SSID, WIFI_PASSWD);

  //初始化 iot，需传入 wifi 的 client，和设备产品信息
  AliyunIoTSDK::begin(espClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET, REGION_ID);

  //绑定一个设备属性回调，当远程修改此属性，会触发LED函数
  AliyunIoTSDK::bindData("Brightness", LED); //主机的板载LED
  // AliyunIoTSDK::bindData("FullAutoModeSwitch", LED);
  // AliyunIoTSDK::bindData("CurtainOperation", LED);
  // AliyunIoTSDK::bindData("FanState", LED);
  // AliyunIoTSDK::bindData("AntiTheft", LED);
}
//-------------------------------------------------------------------------
void display()
{
  //默认：lcd 显示温度
  lcd.setCursor(0, 0); //设置显示指针
  lcd.print("Have a nice day!");
  lcd.setCursor(0, 1);
  lcd.print("T");
  lcd.print(T);
  lcd.print("*C");
  lcd.print(" H");
  lcd.print(RH);
  lcd.print("%");
  delay(500);
  if (antiTheft != antiTheft_prev) // 当切换防盗
  {
    if (antiTheft == 1)
    {
      lcd.setCursor(0, 1);
      lcd.print("Anti-theft on   ");
      delay(800);
    }
    else
    {
      lcd.setCursor(0, 1);
      lcd.print("Anti-theft off   ");
      delay(800);
    }
    antiTheft_prev = antiTheft;
  }
  if (alarmState == 1)
  {
    lcd.setCursor(0, 0); //设置显示指针
    lcd.print("!!!!!!!!!!!!!!!!");
    lcd.setCursor(0, 1); //设置显示指针
    lcd.print("Someone in!!!!!!!");
    delay(800);
  }

  if (autoMode != autoMode_prev) // 当切换自动
  {
    if (autoMode == 1)
    {
      lcd.setCursor(0, 1);
      lcd.print("Anti-theft on   ");
      delay(800);
    }
    else
    {
      lcd.setCursor(0, 1);
      lcd.print("Anti-theft off   ");
      delay(800);
    }
    autoMode_prev = autoMode;
  }

  if (autoMode == 0) //当没开启自动模式，改变数值会自动显示
  {
    {
      if (brightness != brightness_prev)
      {
        lcd.setCursor(0, 0);
        lcd.print("The brightness     ");
        lcd.setCursor(0, 1);
        lcd.print("of lamp is ");
        lcd.print(brightness);
        lcd.print("   ");
        brightness_prev = brightness;
      }
      else if (curtain != curtain_prev)
      {
        lcd.setCursor(0, 0);
        lcd.print("The status of   ");
        lcd.setCursor(0, 1);
        if (fan == 0)
        {
          lcd.print("  curtain: OFF  ");
        }
        else
        {
          lcd.print("  curtain: OPEN ");
        }
        curtain_prev = curtain;
      }
      else if (fan != fan_prev)
      {
        lcd.setCursor(0, 0);
        lcd.print("The speed of   ");
        lcd.setCursor(0, 1);
        lcd.print("fan: ");
        lcd.print(fan);
        fan_prev = fan;
      }
      delay(800);
    }
  }
}

//-------------------------------------------------------------------------

// the loop function runs over and over again forever
void loop()
{
  AliyunIoTSDK::loop(); //必要函数

  /*接受其他arduino传来的数据 */
  String arduinoA_string = "";

  while (toArduinoA.available() > 0)
  {
    // if (toArduinoA.peek() != '\n')
    // {
      arduinoA_string += char(toArduinoA.read());
      delay(5);
    // }

    //解码
    DynamicJsonDocument doc(256); //存储收到的
    deserializeJson(doc, arduinoA_string);
    RH = doc["Humidity"];
    T = doc["Temperature"];
    illumination = doc["Illumination"];
    motion = doc["MotionAlarm"];
    collide = doc["CollideStatus"];
    tilt = doc["OverTiltError"];
    alarmState = doc["AlarmState"];
  }
  //模拟从其它设备读取完毕后的值
  RH = 50;
  T = 25;
  illumination = 200;
  brightness = 100;
  autoMode = 0;
  fan = 50;
  curtain = 1;

  antiTheft = 0;
  motion = 0;
  collide = 0;
  tilt = 0;
  alarmState = 0;

  //显示
  display();
  // 需要求和的完成求和或赋值操作
  RH_sum += RH;
  T_sum += T;
  illumination_sum += illumination;
  motion_sum += motion;
  collide_sum += collide;
  tilt_sum += tilt;
  alarmState_sum += alarmState;
  brightness_prev = brightness;

  // 计数
  count += 1;
  /*向串口打印 */
  // Serial.print("Humidity:"); //向串口打印 Humidity:
  // Serial.print(RH);          //向串口打印湿度数据
  // Serial.print("%");
  // Serial.print("  Temperature:");
  // Serial.print(T); //向串口打印温度数据
  // Serial.println("C");
  // Serial.print("Illumination:");
  // Serial.println(illumination);
  // Serial.print("MotionAlarmState:");
  // Serial.println(motion);
  // Serial.print("CollideStatus");
  // Serial.println(collide);
  // Serial.print("OverTiltError");
  // Serial.println(tilt);
  // Serial.print("AlarmState");
  // Serial.println(alarmState);

  if (millis() - lastMs >= 6000) //每6秒发送一次
  {
    lastMs = millis();
    //发送温度，需要平均
    AliyunIoTSDK::send("CurrentTemperature", T_sum / count);
    //湿度，需要平均
    AliyunIoTSDK::send("CurrentHumidity", RH_sum / count);
    //环境亮度，需要平均
    AliyunIoTSDK::send("Illumination", illumination_sum / count);
    //设备亮度，不需
    AliyunIoTSDK::send("Brightness", brightness);
    // 窗帘状态
    AliyunIoTSDK::send("CurtainOperation", curtain);
    //风扇
    AliyunIoTSDK::send("FanState", fan);
    //红外
    AliyunIoTSDK::send("MotionAlarmState", motion_sum);
    //碰撞
    AliyunIoTSDK::send("CollideStatus", collide_sum);
    //倾斜
    AliyunIoTSDK::send("OverTiltError", tilt_sum);
    //警报
    AliyunIoTSDK::send("AlarmState", alarmState_sum);

    //上报数据清零
    count = 0;
    RH_sum = 0;
    T_sum = 0;
    illumination_sum = 0;
    motion_sum = 0;
    collide_sum = 0;
    tilt_sum = 0;
    alarmState_sum = 0;
  }
}

//wifi 连接-----------------------------------------------------------------
void wifiInit(const char *ssid, const char *passphrase)
{
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, passphrase);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1000);
    Serial.println("WiFi not Connect");
  }
  Serial.println("Connected to AP");
}
//主机板载灯控制函数（阿里云端修改LED属性时触发）-------------------------------------------------------
void LED(JsonVariant L) //固定格式，修改参数L
{
  int Brightness = L["Brightness"]; //参数传入（LED）
  if (Brightness == 0)
  {
    digitalWrite(LED_BUILTIN, HIGH);
  }
  else
  {
    digitalWrite(LED_BUILTIN, LOW);
  }
  Serial.printf("收到的LED是：");
  Serial.println(Brightness);
}

//反控灯光
void BRI(JsonVariant L) //固定格式，修改参数L
{
  int B = L["Brightness"]; //参数传入（LED）
  Serial.printf("收到brightness的参数是：");
  Serial.println(B);
  DynamicJsonDocument data(256);
  data["Brightness"]=B;
  char json_string[256];
  serializeJson(data, json_string);
  toArduinoA..println(json_string);
}
//反控自动
void AUTO(JsonVariant L) //固定格式，修改参数L
{
  int A = L["FullAutoModeSwitch"]; //参数传入（LED）
  Serial.printf("收到的automode参数是：");
  Serial.println(A);
  DynamicJsonDocument data(256);
  data["Brightness"]=A;
  char json_string[256];
  serializeJson(data, json_string);
  toArduinoA..println(json_string);
}
//反控窗帘
void CUR(JsonVariant L) //固定格式，修改参数L
{
  int C = L["CurtainOperation"]; //参数传入（LED）
  Serial.printf("收到的窗帘参数是：");
  Serial.println(C);
  DynamicJsonDocument data(256);
  data["CurtainOperation"]=C;
  char json_string[256];
  serializeJson(data, json_string);
  toArduinoA..println(json_string);
}
//风扇
void FAN(JsonVariant L) //固定格式，修改参数L
{
  int F = L["FanState"]; //参数传入（LED）
  Serial.printf("收到的fanstate是：");
  Serial.println(F);
  DynamicJsonDocument data(256);
  data["FanState"]=F;
  char json_string[256];
  serializeJson(data, json_string);
  toArduinoA..println(json_string);
}
//反控防盗
void ANTI(JsonVariant L) //固定格式，修改参数L
{
  int A = L["AntiTheft"]; //参数传入（LED）
  Serial.printf("收到的防盗参数是：");
  Serial.println(A);
  DynamicJsonDocument data(256);
  data["AntiTheft"]=A;
  char json_string[256];
  serializeJson(data, json_string);
  toArduinoA..println(json_string);
}